package fregat.base.util;

import java.util.ResourceBundle;

/**
 * Class that wraps numerical data.
 * As telegrams has fixed length all data items must use placeholders if no data
 * is set. Num-Data uses '0' as placeholder and aligns right per default.
 *
 * @author Alexander Mann <br><b><i>ECO_L O G</i> &nbsp Logistiksysteme GmbH</b>
 * @version 1.0
 */
public class NumData {
  private int value;
  private int digits;
  private char placeholder = '0';
  private int alignment;
  private boolean undefined;
  public static final int ALIGN_RIGHT = 0;
  public static final int ALIGN_LEFT = 1;
  private static ResourceBundle resource = ResourceBundle.getBundle("at.ecolog.base.util.resource");

  /**
   * Creates numerical data with given value, using the given number of digits, placeholder and alignment.
   *
   * @param value  Numerical value
   * @param digits Number of digits
   * @param placeholder Placeholder character for not used digits
   * @param alignment Alignment of number
   */
  public NumData(int value, int digits, char placeholder, int alignment) {
    this(value, digits);
    this.placeholder = placeholder;
    this.alignment = alignment;
  }

  /**
   * Creates numerical data with the given value, using the given number of digits.
   *
   * @param value  Numerical value
   * @param digits Number of digits
   */
  public NumData(int value, int digits) {
    this.digits = digits;
    this.value = value;
    checkValue();
  }

  /**
   * Creates numerical data by using all numeric values in the given string beginning at the specified position.
   * If no number is found at the specified position the data is initialized with zero.
   * If data only contains placeholders, the instance is marked as undefined (only for placeholder other than '0')
   *
   * @param data   Input string
   * @param start  Position of numerical value in string
   * @param digits Number of digits
   * @param placeholder Placeholder character for not used digits
   * @param alignment Alignment of number
   */
  public NumData(String data, int start, int digits, char placeholder, int alignment) {
    this.placeholder = placeholder;
    this.alignment = alignment;
    this.digits = digits;
    parse(data,start);
  }

  /**
   * Creates numerical data by using all numeric values in the given string beginning at the specified position.
   * If no number is found at the specified position the data is initialized with zero.
   * If data only contains placeholders, the instance is marked as undefined (only for placeholder other than '0')
   *
   * @param data   Input string
   * @param start  Position of numerical value in string
   * @param digits Number of digits
   */
  public NumData(String data, int start, int digits) {
    this.digits = digits;
    parse(data,start);
  }

  private void parse(String data, int start) {
    try {
      int firstDigit = -1;
      int lastDigit = -1;

      if(alignment == ALIGN_LEFT) {
        firstDigit = start;
        int i=start+digits-1;
        while(lastDigit <0 && i>=start) {
          if(data.charAt(i) != placeholder) {
            lastDigit = i+1;
          }
          i--;
        }
      } else {
        lastDigit = start+digits;
        int i=start;
        while(firstDigit <0 && i<start+digits) {
          if(data.charAt(i) != placeholder) {
            firstDigit = i;
          }
          i++;
        }

      }
      if(firstDigit > 0 && lastDigit >0) {
        setValue(Integer.parseInt(data.substring(firstDigit,lastDigit)));
      } else {
        if(placeholder != '0') {
          setUndefined(true);
        }
      }

    } catch (Exception ex) {
      Logger.getDefaultCategory().warn("NumData(...) - " + resource.getString("NumData_constructor_1") +
        " (" + data + ")," + start + "," + digits);
    } 
  }

  /**
   * Sets the value. If value has more digits than defined the value is set to zero.
   *
   * @param value Value to set
   */
  public void setValue(int value) {
    this.value = value;
    checkValue();
  }

  /**
   * @return Value
   */
  public int intValue() {
    return value;
  }

  /**
   * Set where data should be.
   * Use the constants <code>ALIGN_LEFT,ALIGN_RIGHT</code>.
   *
   * @param i
   */
  public void setAlignment(int i) {
    alignment = i;
  }

  /**
   * Returns the string representation of the value by adding leading zeros if
   * value has less digits as defined.
   *
   * @return String representation
   */
  public String toString() {
    StringBuffer buffer = new StringBuffer();

    if(!undefined) {
      buffer.append(Integer.toString(value));
    }

    while (buffer.length() < digits) {
      if (alignment == ALIGN_RIGHT) {
        buffer.insert(0, placeholder);
      } else {
        buffer.append(placeholder);
      }
    }
    return buffer.toString().substring(0, digits);
  }

  /**
   * Compares the numerical data to another instance.
   *
   * @param data Another <code>NumData</code> instance
   * @return True, if equal
   */
  public boolean equals(NumData data) {
    return value == data.intValue();
  }

  /**
   * The numerical valueis not defined. String representation is filled with placeholder.
   * @param b True, if undefined
   */
  public void setUndefined(boolean b) {
    undefined = b;
  }

  /**
   * @return True, if value is undefined
   */
  public boolean isUndefined() {
    return undefined;
  }

  private void checkValue() {
    if (!(value < (int) Math.pow(10, digits))) value = 0;
  }


  /**
   * @return Character used as placeholder
   */
  public char getPlaceholder() {
    return placeholder;
  }

  /**
   * @return Alignment of data (returns constants <code>ALIGN_LEFT,ALIGN_RIGHT</code>)
   */
  public int getAlignment() {
    return alignment;
  }
}
